package com.common.utils;

import org.apache.commons.lang3.time.DateFormatUtils;

import java.lang.management.ManagementFactory;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 时间工具类
 */
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
    // 日期格式，年份，例如：2004，2008
    public static final String DATE_FORMAT_YYYY = "yyyy";
    // 日期格式，日月，例如：2004，2008
    public static final String DATE_FORMAT_MM_dd = "MM-dd";
    // 日期格式，年份和月份，例如：200707，200808
    public static final String DATE_FORMAT_YYYYMM = "yyyyMM";

    // 日期格式，年份和月份，例如：200707，2008-08
    public static final String DATE_FORMAT_YYYY_MM = "yyyy-MM";

    // 日期格式，年月日，例如：20050630，20080808
    public static final String DATE_FORMAT_YYYYMMDD = "yyyyMMdd";
    // 日期格式，年月日，例如：050630，080808
    public static final String DATE_FORMAT_YYMMDD = "yyMMdd";
    //
    public static final String DATE_FORMAT_YYYYMMDDHHmm = "yyyyMMddHHmm";

    // 日期格式，年月日，用横杠分开，例如：2006-12-25，2008-08-08
    public static final String DATE_FORMAT_YYYY_MM_DD = "yyyy-MM-dd";

    /// 日期格式，年月日，用横杠分开，例如：06-12-25，08-08-08
    public static final String DATE_FORMAT_YY_MM_DD = "yy-MM-dd";

    // 日期格式，年月日时分，例如：20001230 12:00，20080808 20:08
    public static final String DATE_TIME_FORMAT_YYYYMMDD_HH_MI = "yyyyMMdd HH:mm";

    // 日期格式，年月日时分，例如：2000-12-30 12:00，2008-08-08 20:08
    public static final String DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI = "yyyy-MM-dd HH:mm";

    // 日期格式，年月日时分秒，例如：20001230120000，20080808200808
    public static final String DATE_TIME_FORMAT_YYYYMMDDHHMISS = "yyyyMMddHHmmss";

    // 日期格式，年月日时分秒，年月日用横杠分开，时分秒用冒号分开，
    // 例如：2005-05-10 23：20：00，2008-08-08 20:08:08
    public static final String DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS = "yyyy-MM-dd HH:mm:ss";

    // 日期格式，年月日时分秒毫秒，例如：20001230120000123，20080808200808456
    public static final String DATE_TIME_FORMAT_YYYYMMDDHHMISSSSS = "yyyyMMddHHmmssSSS";

    public static final String DATE_TIME_FORMAT_YYYY年MM月DD日 = "yyyy年MM月dd日";

    public static final String DATE_FORMAT_POINTYYYYMMDD = "yyyy.MM.dd";
    public static final String DATE_FORMAT_POINTYYYYMM = "yyyy.MM";

    public static final String DATE_FORMAT_MMDDHHMI = "MM-dd HH:mm";

    public static final String DATE_FORMAT_YY_MM_DD_HH_MM = "yy-MM-dd HH:mm";
    public static final String DATE_TIME_FORMAT_MM月DD日 = "MM月dd日";
    public static String YYYY = "yyyy";

    public static String YYYY_MM = "yyyy-MM";

    public static String YYYY_MM_DD = "yyyy-MM-dd";

    public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
    public static String YYYYMMDD = "yyyyMMdd";

    public static String YYYYMMDD_HHMM = "yyyyMMdd-HHmm";

    public static String YYYYMMDDHHMMSSSSS = "yyyyMMddHHmmssSSS";

    public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    private static String[] parsePatterns = {
            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};

    public static String parseDateToStr(Date time, String timeFromat) {
        if (timeFromat == null || timeFromat.isEmpty()) timeFromat = "yyyy-MM-dd HH:mm:ss";
        DateFormat dateFormat = new SimpleDateFormat(timeFromat);
        return dateFormat.format(time);
    }

    public static String parseTimestampToStr(Timestamp timestamp, String timeFromat) {
        SimpleDateFormat df = new SimpleDateFormat(timeFromat);
        return df.format(timestamp);
    }

    public static String timeStamp2Date(String seconds, String format) {
        if (seconds == null || seconds.isEmpty() || seconds.equals("null")) {
            return "";
        }
        if (format == null || format.isEmpty()) format = "yyyy-MM-dd HH:mm:ss";
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(new Date(Long.valueOf(seconds + "000")));
    }

    /**
     * @param time
     * @param timeFromat
     * @param defaultValue 默认值,如果为空返回当前时间的对应格式日期。
     * @return
     * @author zhenhui
     */
    public static String parseDateToStr(Date time, String timeFromat, final Date defaultValue) {
        try {
            DateFormat dateFormat = new SimpleDateFormat(timeFromat);
            return dateFormat.format(time);
        } catch (Exception e) {
            if (defaultValue != null)
                return parseDateToStr(defaultValue, timeFromat);
            else
                return parseDateToStr(new Date(), timeFromat);
        }
    }

    /**
     * 获取当前Date型日期
     *
     * @return Date() 当前日期
     */
    public static Date getNowDate() {
        return new Date();
    }

    /**
     * 获取当前日期, 默认格式为yyyy-MM-dd
     *
     * @return String
     */
    public static String getDate() {
        return dateTimeNow(YYYY_MM_DD);
    }

    public static final String getTime() {
        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
    }

    public static final String dateTimeNow() {
        return dateTimeNow(YYYYMMDDHHMMSS);
    }

    public static final String dateTimeNow(final String format) {
        return parseDateToStr(format, new Date());
    }

    public static final String dateTime(final Date date) {
        return parseDateToStr(YYYY_MM_DD, date);
    }

    public static final String parseDateToStr(final String format, final Date date) {
        return new SimpleDateFormat(format).format(date);
    }

    public static final Date dateTime(final String format, final String ts) {
        try {
            return new SimpleDateFormat(format).parse(ts);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    public static Date parseStrToDate(String time, String timeFromat) {
        if (time == null || time.equals("")) {
            return null;
        }
        Date date = null;
        try {
            if (timeFromat == null || timeFromat.isEmpty()) timeFromat = "yyyy-MM-dd HH:mm:ss";
            DateFormat dateFormat = new SimpleDateFormat(timeFromat);
            date = dateFormat.parse(time);
        } catch (Exception e) {

        }
        return date;
    }

    /**
     * 日期路径 即年/月/日 如2018/08/08
     */
    public static final String datePath() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyy/MM/dd");
    }

    /**
     * 日期路径 即年/月/日 如20180808
     */
    public static final String dateTime() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyyMMdd");
    }

    /**
     * 日期型字符串转化为日期 格式
     */
    public static Date parseDate(Object str) {
        if (str == null) {
            return null;
        }
        try {
            return parseDate(str.toString(), parsePatterns);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 获取服务器启动时间
     */
    public static Date getServerStartDate() {
        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
        return new Date(time);
    }

    /**
     * 计算两个时间差
     */
    public static String getDatePoor(Date endDate, Date nowDate) {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        // long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - nowDate.getTime();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
        long min = diff % nd % nh / nm;
        // 计算差多少秒//输出结果
        // long sec = diff % nd % nh % nm / ns;
        return day + "天" + hour + "小时" + min + "分钟";
    }

    /**
     * 方法名: </br>
     * 详述: </br>获取上周几的日期
     * 开发人员：tm</br>
     * 创建时间：Apr 27, 2015</br>
     *
     * @return
     */
    public static Date getLastWeekDay(int weekDay) {
        Calendar cal = Calendar.getInstance();  //n为推迟的周数，1本周，-1向前推迟一周，2下周，依次类推
        int n = -1;
        String friday;
        cal.add(Calendar.DATE, n * 7);  //想周几，这里就传几Calendar.MONDAY（TUESDAY...）
        if (weekDay == 1) cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        else if (weekDay == 2) cal.set(Calendar.DAY_OF_WEEK, Calendar.TUESDAY);
        else if (weekDay == 3) cal.set(Calendar.DAY_OF_WEEK, Calendar.WEDNESDAY);
        else if (weekDay == 4) cal.set(Calendar.DAY_OF_WEEK, Calendar.THURSDAY);
        else if (weekDay == 5) cal.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
        else if (weekDay == 6) cal.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
        else if (weekDay == 7) cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
        friday = new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime());
        return parseStrToDate(friday, DATE_FORMAT_YY_MM_DD);
    }

    /**
     * 计算两个日期之间的天数
     *
     * @param startDate
     * @param endDate
     * @return long
     * @author tm
     * @date 2022-10-17 2:59
     */
    public static long calDay(Date startDate, Date endDate) {
        long daysBetween = (endDate.getTime() - startDate.getTime() + 1000000) / (3600 * 24 * 1000);
        return daysBetween;
    }

    public static long calSecond(Date startDate, Date endDate) {
        long a = endDate.getTime();
        long b = startDate.getTime();
        int c = (int) ((a - b) / 1000);
        return c;
    }

    /**
     * 取得当前日期所在周的最后一天
     *
     * @param date
     * @return
     */
    public static Date getLastDayOfWeek(Date date) {
        Calendar c = new GregorianCalendar();
        c.setFirstDayOfWeek(Calendar.MONDAY);
        c.setTime(date);
        c.set(Calendar.DAY_OF_WEEK, c.getFirstDayOfWeek() + 6); // Sunday
        return c.getTime();
    }

    /**
     * * 判断当前日期为星期几 *
     *
     * @param date *
     * @return
     */
    public static int dayOfWeek(Date date) {
        Calendar aCalendar = Calendar.getInstance();
        aCalendar.setTime(date);
        int weekDay = aCalendar.get(Calendar.DAY_OF_WEEK);
        return weekDay;
    }

    /**
     * 取得当前日期所在周的第一天
     *
     * @param date
     * @return
     */
    public static Date getFirstDayOfWeek(Date date) {
        Calendar c = new GregorianCalendar();
        c.setFirstDayOfWeek(Calendar.MONDAY);
        c.setTime(date);
        c.set(Calendar.DAY_OF_WEEK, c.getFirstDayOfWeek());
        return c.getTime();
    }

    /**
     * 得到某年某月的第一天
     *
     * @param year
     * @param month
     * @return
     */
    public static Date getFirstDayOfMonth(int year, int month) {
        month = month - 1;
        Calendar c = Calendar.getInstance();
        c.set(Calendar.YEAR, year);
        c.set(Calendar.MONTH, month);

        int day = c.getActualMinimum(c.DAY_OF_MONTH);

        c.set(Calendar.DAY_OF_MONTH, day);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    /**
     * 提到某年某月的最后一天
     *
     * @param year
     * @param month
     * @return
     */
    public static Date getLastDayOfMonth(int year, int month) {
        month = month - 1;
        Calendar c = Calendar.getInstance();
        c.set(Calendar.YEAR, year);
        c.set(Calendar.MONTH, month);
        int day = c.getActualMaximum(c.DAY_OF_MONTH);
        c.set(Calendar.DAY_OF_MONTH, day);
        c.set(Calendar.HOUR_OF_DAY, 23);
        c.set(Calendar.MINUTE, 59);
        c.set(Calendar.SECOND, 59);
        c.set(Calendar.MILLISECOND, 999);
        return c.getTime();
    }

    /**
     * 根据日期取得星期
     * add by wds
     *
     * @param date
     * @return
     */
    public static String getWeekBydate(Date date) {
        String[] weekDays = {"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);

        int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (w < 0)
            w = 0;

        return weekDays[w];
    }

    /**
     * 方法名: </br>
     * 详述:获取昨天的日期 </br>
     * 开发人员：zql</br>
     * 创建时间：2018-7-9 下午3:39:41</br>
     *
     * @return
     */
    public static Date getYesterdayDate() {
        Calendar c = Calendar.getInstance();
        c.add(Calendar.DATE, -1);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    /**
     * 方法名: </br>
     * 详述:获取昨天的日期 </br>
     * 开发人员：zql</br>
     * 创建时间：2018-7-9 下午3:39:41</br>
     *
     * @return
     */
    public static Date getYesterdayDate(int i) {
        Calendar c = Calendar.getInstance();
        c.add(Calendar.DATE, i);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    /**
     * 判断时间1是否在时间2之前
     *
     * @param date1
     * @param date2
     * @return
     */
    public static boolean compareTwoTimeBefore(Date date1, Date date2) {
        boolean flag = false;
        Calendar c1 = Calendar.getInstance();
        c1.setTime(date1);
        Calendar c2 = Calendar.getInstance();
        c2.setTime(date2);
        if (c1.before(c2) || c1.equals(c2)) {
            flag = true;
        }
        return flag;
    }

    /**
     * 计算两个时间相差多少分钟
     *
     * @param startDate
     * @param endDate
     * @return long
     * @author tm
     * @date 2022-12-19 22:22
     */
    public static long calMinute(Date startDate, Date endDate) {
        long daysBetween = (endDate.getTime() - startDate.getTime()) / (60 * 1000);
        return daysBetween;
    }

    /**
     * 获取某个date中的年份
     *
     * @param date
     * @return String
     * @author tm
     * @date 2023-04-30 3:30
     */
    public static String getYear(Date date) {
        String year = String.format("%tY", date);
        return year;
    }

    /**
     * 获取某个date中的月份
     *
     * @param date
     * @return String
     * @author tm
     * @date 2023-04-30 3:30
     */
    public static String getMonth(Date date) {
        String month = String.format("%tm", date);
        return month;
    }

    /**
     * 获取某个date中的日期
     *
     * @param date
     * @return String
     * @author tm
     * @date 2023-04-30 3:30
     */
    public static String getDate(Date date) {
        String day = String.format("%te", date);
        return day;
    }

    /**
     * 获得指定时间加减参数后的日期(不计算则输入0)
     *
     * @param date        指定日期
     * @param year        年数，可正可负
     * @param month       月数，可正可负
     * @param day         天数，可正可负
     * @param hour        小时数，可正可负
     * @param minute      分钟数，可正可负
     * @param second      秒数，可正可负
     * @param millisecond 毫秒数，可正可负
     * @return 计算后的日期
     */
    public static Date addDate(Date date, int year, int month, int day, int hour, int minute, int second, int millisecond) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.YEAR, year);//加减年数
        c.add(Calendar.MONTH, month);//加减月数
        c.add(Calendar.DATE, day);//加减天数
        c.add(Calendar.HOUR, hour);//加减小时数
        c.add(Calendar.MINUTE, minute);//加减分钟数
        c.add(Calendar.SECOND, second);//加减秒
        c.add(Calendar.MILLISECOND, millisecond);//加减毫秒数

        return c.getTime();
    }

    /**
     * 两个时间相差距离多少天多少小时多少分多少秒
     *
     * @param str1 时间参数 1 格式：1990-01-01 12:00:00
     * @param str2 时间参数 2 格式：2009-01-01 12:00:00
     * @return String 返回值为：xx天xx小时xx分xx秒
     */
    public static List<Long> getDistanceTime(String str1, String str2) {
        List<Long> list = new ArrayList<>();
        DateFormat df = new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS);
        Date one;
        Date two;
        long day = 0;
        long hour = 0;
        long min = 0;
        long sec = 0;
        try {
            one = df.parse(str1);
            two = df.parse(str2);
            long time1 = one.getTime();
            long time2 = two.getTime();
            long diff;
            if (time1 < time2) {
                diff = time2 - time1;
            } else {
                diff = time1 - time2;
            }
            day = diff / (24 * 60 * 60 * 1000);
            hour = (diff / (60 * 60 * 1000) - day * 24);
            min = ((diff / (60 * 1000)) - day * 24 * 60 - hour * 60);
            sec = (diff / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        list.add(day);
        list.add(hour);
        list.add(min);
        list.add(sec);
        return list;
//        return day + "天" + hour + "小时" + min + "分" + sec + "秒";
    }

    /**
     * 获取某日期的年份
     *
     * @param date
     * @return
     */
    public static Integer getYearInt(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.YEAR);
    }

    /**
     * 获取某日期的月份
     *
     * @param date
     * @return
     */
    public static Integer getMonthInt(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.MONTH) + 1;
    }

    public static Integer getDay(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int day = cal.get(Calendar.DATE);//获取日
        return day;
    }

    public static Integer getHour(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int hour = cal.get(Calendar.HOUR_OF_DAY);
        return hour;
    }

    public static Integer getMinute(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int minute = cal.get(Calendar.MINUTE);
        return minute;
    }

    public static Integer getSecond(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int second = cal.get(Calendar.SECOND);
        return second;
    }

    public static Boolean compareIsSameDay(Date date1, Date date2) {
        boolean flag = false;
        int year1 = getYearInt(date1);
        int year2 = getYearInt(date2);
        if (year1 == year2) {
            int month1 = getMonthInt(date1);
            int month2 = getMonthInt(date2);
            if (month1 == month2) {
                int day1 = getDay(date1);
                int day2 = getDay(date2);
                if (day1 == day2) return true;
            }
        }
        return flag;
    }

    public static void main(String[] args) {
//        Date date1 = parseStrToDate("2022-12-20 00:06:01",DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS);
//        Date date2 = parseStrToDate("2022-12-20 00:05:01",DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS);
//        System.out.println(compareTwoTimeBefore(date1,date2));
        String date2 = "2023-07-10 15:54:33";
        String date1 = "2023-07-13 15:54:33";
//        List<Long> list = getDistanceTime(date1,date2);
//        System.out.println(list);
        System.out.println(getFirstDayOfMonth(2023,9));
        System.out.println(getLastDayOfMonth(2023,9));
    }

}
